#
# Rules for building a program target
#
# The following variables must be passed when calling this file:
#
#   BASE_DIR         - base directory of the build system
#   REP_DIR          - source repository of the program
#   PRG_DIR          - directory of the program's target.mk file
#   REPOSITORIES     - repositories providing libs and headers
#   DEFAULT_VPATH    - default source file search directory
#   INSTALL_DIR      - final install location
#   VERBOSE          - build verboseness modifier
#   VERBOSE_DIR      - verboseness modifier for changing directories
#   VERBOSE_MK       - verboseness of make calls
#   BUILD_BASE_DIR   - base of build directory tree
#   LIB_CACHE_DIR    - library build cache location
#   LIB_PROGRESS_LOG - library build log file
#

#
# Prevent target.mk rules to be executed as default rule
#
all::

#
# Function that searches for files in all
# repositories and returns the first match.
#
select_from_repositories = $(firstword $(foreach REP,$(REPOSITORIES),$(wildcard $(REP)/$(1))))

#
# Include target build instructions
#
include $(PRG_DIR)/target.mk

#
# Include specifics configuration
#
-include $(call select_from_repositories,etc/specs.conf)
-include $(BUILD_BASE_DIR)/etc/specs.conf

#
# Include specifics for platforms, kernel APIs, etc.
#
include $(foreach SPEC,$(SPECS),$(call select_from_repositories,mk/spec-$(SPEC).mk))

#
# Include lib-import description files
#
include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk))

#
# Check if the requirements of the target are satisfied
#
UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES))
ifneq ($(UNSATISFIED_REQUIREMENTS),)
all::
	@$(ECHO) "Skip program $(TARGET) because it requires $(DARK_COL)$(UNSATISFIED_REQUIREMENTS)$(DEFAULT_COL)"
else
all:: all_sequence
endif

SRC_CC += $(PRG_SRC_CC)
SRC_C  += $(PRG_SRC_C)
SRC_S  += $(PRG_SRC_S)
LIBS   += $(PRG_LIBS)

vpath % $(DEFAULT_VPATH)

include $(BASE_DIR)/mk/global.mk

#
# Set lib cache directory when building in the source tree
#
LIB_CACHE_DIR ?= $(realpath $(BASE_DIR)/var/libcache)

#
# Define directory to where we create all <libname>.lib.a symbolic links
#
TARGET_DIR := $(shell pwd)
TARGET_LOC := $(TARGET_DIR)/$(TARGET)

#
# Build libraries that we depend on
#
all_sequence::
	$(VERBOSE_MK)$(MAKE) $(VERBOSE_DIR)  -f $(BASE_DIR)/mk/build_libs.mk \
	  BASE_DIR=$(BASE_DIR) \
	  BUILD_BASE_DIR=$(BUILD_BASE_DIR) \
	  TARGET_DIR=$(TARGET_DIR) \
	  REPOSITORIES="$(REPOSITORIES)" \
	  VERBOSE=$(VERBOSE) \
	  VERBOSE_DIR=$(VERBOSE_DIR) \
	  VERBOSE_MK=$(VERBOSE_MK) \
	  LIB_CACHE_DIR=$(LIB_CACHE_DIR) \
	  LIB_PROGRESS_LOG=$(LIB_PROGRESS_LOG) \
	  $(addsuffix .lib.a,$(LIBS))
#
# Make sure all libraries are build before building the target.
# Unfortunately, there is no way to depend on libraries that do not
# yet exist, creating problems with parallel builds.
#
.NOTPARALLEL:

include $(BASE_DIR)/mk/generic.mk

ifeq ($(INSTALL_DIR),)
all_sequence:: $(TARGET)
else
all_sequence:: $(INSTALL_DIR)/$(TARGET)
endif

$(TARGET)::
	$(MSG_PRG)$(TARGET)

#
# The $(wildcard) operator is evaluated only at the beginning of the
# process and some *.lib.a files that are created afterward may be
# missing. Thus, we specify the *.lib.a to the linker instead of $^.
# The dependencies are based on the LIBS variable and the currently
# existing *.lib.a files. The LIBS variable triggers the build of
# not-yet built libraries but it does not contain any sub-libraries.
# By incorporating also all existing *.lib.a files, any sub-libraries
# are also taken into account.
#
find_libs_in_pwd = $(GNU_FIND) -mindepth 1 -maxdepth 1 -name "*.lib.a"
$(TARGET_LOC):: $(shell $(find_libs_in_pwd)) $(addsuffix .lib.a,$(LIBS)) $(TARGET) $(OBJECTS)
	$(MSG_LINK)$(TARGET)
	$(VERBOSE)$(CXX) $(CXX_LINK_OPT) -Wl,--start-group `$(find_libs_in_pwd)` $(OBJECTS) -Wl,--end-group $(EXT_OBJECTS) -o $@

#
# Install binary if INSTALL_DIR is set.
#
ifneq ($(INSTALL_DIR),)
$(INSTALL_DIR)/$(TARGET): $(TARGET_LOC)
	$(MSG_INST)$(TARGET)
	$(VERBOSE)ln -s -f $(TARGET_LOC) $@
	$(VERBOSE)chmod 755 $@
endif

clean cleanall::
	$(MSG_CLEAN)$(TARGET)
	$(VERBOSE)$(RM) -f $(OBJECTS) $(TARGET) $(INSTALL_DIR)/$(TARGET)
	$(VERBOSE)$(RM) -f *.lib.a $(TARGET).o
	$(VERBOSE)$(RM) -f *.d *.i *.ii *.s

